package com.bblocks.util;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * 业务锁
 */
@Slf4j
@Component("bblocksRedissonLock")
//@ConditionalOnProperty(name = "spring.redis.redisson.enabled", matchIfMissing = true)
@ConditionalOnBean(name = "redissonConfig")
public class DistributedRedisLock {
    private static final String LOCK_TITLE_PRE = "redisLock:";
    private static final String LOCK_MODULE_COMMON = "common";

    @Autowired
    private RedissonClient redissonClient;

	/**
	 * 锁（直到成功）
	 * @param module
	 * @param lockName
	 * @param lockSeconds
	 * @return
	 */
    public boolean acquireSeconds(String module, String lockName, int lockSeconds){
        return acquire(module,  lockName,  lockSeconds,TimeUnit.SECONDS);
    }

	/**
	 * 尝试锁（尝试最大时间100ms）
	 * @param module
	 * @param lockName
	 * @param lockSeconds
	 * @return
	 */
	public boolean acquireSecondsTry(String module, String lockName, int lockSeconds){
		return acquireWithTryTime(module,  lockName,  lockSeconds * 1000,100,TimeUnit.MILLISECONDS);
	}

	/**
	 * 锁（直到成功）
	 * @param module
	 * @param lockName
	 * @param lockTime
	 * @param timeUnit
	 * @return
	 */
    public boolean acquire(String module, String lockName, int lockTime, TimeUnit timeUnit){
        //声明key对象
        String key =  LOCK_TITLE_PRE + getFinalModule(module)+":"+lockName;
        //获取锁对象
        RLock mylock = redissonClient.getLock(key);
        //加锁，并且设置锁过期时间，防止死锁的产生
        mylock.lock(lockTime, timeUnit);
        log.info("======lock======"+Thread.currentThread().getName());
        //加锁成功
        return  true;
    }

	/**
	 * 尝试锁
	 * @param module
	 * @param lockName
	 * @param lockTime 锁定时间
	 * @param lockWaitTime 尝试锁等待时间（超时则失败）
	 * @param timeUnit
	 * @return
	 */
	public boolean acquireWithTryTime(String module, String lockName, int lockTime,int lockWaitTime, TimeUnit timeUnit){
		//声明key对象
		String key =  LOCK_TITLE_PRE + getFinalModule(module)+":"+lockName;
		//获取锁对象
		RLock mylock = redissonClient.getLock(key);
		//加锁，并且设置锁过期时间，防止死锁的产生
		try {
			return mylock.tryLock(lockTime, lockWaitTime, timeUnit);
		} catch (InterruptedException e) {
			log.warn("锁：{} 获取失败！",key);
			return false;
		}
	}


    //锁的释放
    public  void release(String module, String lockName){
        //必须是和加锁时的同一个key
        String key = LOCK_TITLE_PRE + getFinalModule(module)+":"+lockName;
        //获取所对象
        RLock mylock = redissonClient.getLock(key);
		release(mylock);
    }

	/**
	 * 解锁
	 * @param mylock
	 */
	public  void release(RLock mylock){
		if(mylock.isLocked())
			mylock.unlock();
		//释放锁（解锁）
		log.info("======unlock======"+Thread.currentThread().getName());
	}

    private String getFinalModule(String module){
        if(StrUtil.isNotEmpty(module))
            return module;
        else
            return LOCK_MODULE_COMMON;
    }

}
